﻿using Ndns.Packet.Abstractions;
using System.Buffers;
using System.Collections.Generic;
using System.IO;

namespace Ndns.Packet.Parser
{
    public class DnsPacketParser
    {

        private readonly ArrayPool<byte> _arrayPool;
        private readonly DnsHostNameParser _hostNameParser;
        private readonly DnsQueryParser _queryParser;
        private readonly DnsResourceRecordParser _resourceRecordParser;

        public DnsPacketParser() : this(null) { }
        public DnsPacketParser(ArrayPool<byte> arrayPool)
        {
            _arrayPool = arrayPool;
            _hostNameParser = new DnsHostNameParser(_arrayPool);
            _queryParser = new DnsQueryParser(_hostNameParser, _arrayPool);
            _resourceRecordParser = new DnsResourceRecordParser(_hostNameParser, _arrayPool);

        }

        public bool TryParse(Stream stream, out DnsPacket packet, out int count)
        {
            packet = new DnsPacket();
            count = 0;
            int offset = 0;
            //获取DNS头部
            int transactionID = stream.ReadNetworkUInt16();
            int flag = stream.ReadNetworkUInt16();
            if (!PacketEndOfStreamException.CheckValue(flag))
            {
                return false;
            }
            offset += 4;
            packet.TransactionID = (ushort)transactionID;
            packet.Flag = (DnsPacketFlag)flag;
            
            //获取各部分数量
            int cQueries, cAnswerRRs, cAuthoritativeNSs, cAdditionalRRs;
            cQueries = stream.ReadNetworkUInt16();
            cAnswerRRs = stream.ReadNetworkUInt16();
            cAuthoritativeNSs = stream.ReadNetworkUInt16();
            cAdditionalRRs = stream.ReadNetworkUInt16();
            if (!PacketEndOfStreamException.CheckValue(cAdditionalRRs))
            {
                return false;
            }
            offset += 8;

            //获取各个部分
            var symbols = new Dictionary<DnsHostNamePointer, DnsHostName>();
            for (int i = 1; i <= cQueries; i++)
            {
                if (!_queryParser.TryParse(stream, symbols, ref offset, out var query))
                    return false;
                packet.Queries.Add(query);
                count = offset;
            }
            for (int i = 1; i <= cAnswerRRs; i++)
            {
                if (!_resourceRecordParser.TryParse(stream, symbols, ref offset, out var record))
                    return false;
                packet.AnswerRRs.Add(record);
                count = offset;
            }
            for (int i = 1; i <= cAuthoritativeNSs; i++)
            {
                if (!_resourceRecordParser.TryParse(stream, symbols, ref offset, out var record))
                    return false;
                packet.AuthoritativeNSs.Add(record);
                count = offset;
            }
            for (int i = 1; i <= cAdditionalRRs; i++)
            {
                if (!_resourceRecordParser.TryParse(stream, symbols, ref offset, out var record))
                    return false;
                packet.AdditionalRRs.Add(record);
                count = offset;
            }

            // 返回
            return true;
        }
    }

    /*
    public static bool TryParse(ArraySegment<byte> buffer, out int count, out DnsPacket packet)
    {
        throw null;
    }

    public static bool TryFillIn(this DnsPacket packet, ArraySegment<byte> buffer, out int count)
    {
        throw null;
    }
    */
}
